﻿/*
    Copyright 2010, 2011 Eric Wong
	contact@optimalcycling.com
	http://www.optimalcycling.com
	Optimal Cycling - Advanced power pacing program for cyclists
	
	This file is part of Optimal Cycling.

    Optimal Cycling is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Optimal Cycling is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Optimal Cycling.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _FILE_OPTIONS_H
#define _FILE_OPTIONS_H


// Enable to allow for varying significance of CCAP rates
// e.g.: Maximal CCAP and non-same increasing and decreasing multipliers
// Otherwise, the absolute value of CCAP is used with no limits
//#define CCAP_RATE_TRANSFORMS
//#define CCAP_MAXIMAL_POWER_RATES

// Allow us to easily switch between float and doubles. Uncomment to use doubles.
// Must also set this same preprocessor directive in the calling code.
// Floats have 7 sig digs, doubles have 16 sig digs
//#define REAL_IS_DOUBLE

// Enable to use the Kahan Summation algorithm for increased summing accuracy in critical areas. Important for single precision.
#define KAHAN_SUMMATION

// Enable printf on AMD platforms
//#pragma OPENCL EXTENSION cl_amd_printf : enable

// For debugging with regular C code using OpenMP for parallel processing
#define OMP_NUM_THREADS 8

// OpenCL specs don't allow size_t vars in the kernel arguments
#define sizeT uint

#ifndef __OPENCL_VERSION__

	#include <math.h>	
	#include <float.h>

	#ifdef _MSC_VER		
		#include <omp.h>
		#define ulong64 unsigned long long
		#define long64 long long

		// Need to be careful about the bitness of integer types or the RNG and array size limits
		// will not be consistent between OpenCL and standard C/C++
		#define MAX_UINT 4294967295		// 32bit
		//#define MAX_UINT UINT_MAX	// 4294967295		// 32bit
		#define MAX_INT INT_MAX		// 2147483647		// 32bit
		#define MAX_LONG _I64_MAX	// 9223372036854775807	// 64bit, 0x7FFFFFFFFFFFFFFF
		#define MIN_LONG _I64_MIN	// -9223372036854775808	// 64bit, 0x8000000000000000
		#define MAX_ULONG 0xffffffffffffffff	//	18446744073709551615
	#else
		// __GNUC__
		#define ulong64 unsigned long long int
		#define long64 long long int

		// Need to be careful about the bitness of integer types or the RNG and array size limits
		// will not be consistent between OpenCL and standard C/C++
		#define MAX_UINT 4294967295		// 32bit
		#define MAX_INT 2147483647		// 32bit
		#define MAX_LONG 9223372036854775807	// 64bit, 0x7FFFFFFFFFFFFFFF
		#define MIN_LONG -9223372036854775808	// 64bit, 0x8000000000000000
		#define MAX_ULONG 0xffffffffffffffff	//	18446744073709551615
	#endif

	// We are using a C/C++ compiler
	#define __global
	#define __constant
	#define __kernel

	//#ifndef __cplusplus
		#define inline
	//#endif	

	typedef unsigned int uint;

	typedef struct 
	{
		unsigned int s0, s1;
	} uint2;

	typedef struct 
	{
		unsigned int s0, s1, s2, s3;
	} uint4;

	typedef struct 
	{
		unsigned int s0, s1, s2, s3, s4, s5, s6, s7;
	} uint8;

	#ifdef REAL_IS_DOUBLE

		// Epsilons: http://msdn.microsoft.com/en-us/library/k15zsh48.aspx
		// Type Ranges: http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx

		// 2.2204460492503131e-016
		#define EPSILON_REAL DBL_EPSILON
		#define SMALL_REAL (1.0 * EPSILON_REAL)
		
		// 1.7976931348623158e+308
		#define MAX_REAL DBL_MAX 
		#define LARGE_REAL	FLT_MAX

		// 2.2250738585072014e-308
		#define MIN_REAL DBL_MIN	

		// log base 2 of MAX_REAL
		// Use 1024 for Microsoft spec
		#define QUICKSORT_STACK_SIZE 1024

		typedef double real;

		typedef struct 
		{
			double s0, s1;
		} double2;
		typedef double2 real2;

		typedef struct 
		{
			double s0, s1, s2, s3;
		} double4;
		typedef double4 real4;

		typedef struct 
		{
			double s0, s1, s2, s3, s4, s5, s6, s7;
		} double8;
		typedef double8 real8;

	#else	// REAL_IS_DOUBLE

		// Epsilons: http://msdn.microsoft.com/en-us/library/k15zsh48.aspx
		// Type Ranges: http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx

		// 1.192092896e-07F
		#define EPSILON_REAL FLT_EPSILON
		#define SMALL_REAL (1.0 * EPSILON_REAL)
		
		// 3.402823466e+38F
		#define MAX_REAL FLT_MAX
		#define LARGE_REAL	FLT_MAX

		// 1.175494351e-38F
		#define MIN_REAL FLT_MIN	

		// log base 2 of MAX_REAL
		// Use 128 for Microsoft spec
		#define QUICKSORT_STACK_SIZE 128

		typedef float real;

		typedef struct 
		{
			float s0, s1;
		} float2;
		typedef float2 real2;

		typedef struct 
		{
			float s0, s1, s2, s3;
		} float4;
		typedef float4 real4;

		typedef struct 
		{
			float s0, s1, s2, s3, s4, s5, s6, s7;
		} float8;
		typedef float8 real8;
	#endif		// REAL_IS_DOUBLE	

	#define get_global_id(a) 0
	#define get_global_size(a) 1

	#define real_divide(a, b) ((a) / (b))
	#define real_rsqrt(a) (1.0/sqrt(a))
	#define real_sqrt(a) sqrt(a)
	#define real_log(a) log(a)
	#define real_powr(a, b) pow(a, b)
	#define real_tan(a) tan(a)
	#define mix(a, b, control) ((a) * (1.0 - (control)) + (b) * (control))
	#define pown(a, b) pow(a, b)
	#define powr(a, b) pow(a, b)
	#define min(a, b) ((a) < (b) ? (a) : (b))

	#ifdef _MSC_VER
		#define isfinite(a) _finite(a)
	#else
		#define isfinite(a) (!(isinf(a) || isnan(a)))
	#endif

	#define clamp(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
	#define real_exp(a) exp(a)

	#define real4_length(a) (sqrt((a).s0 * (a).s0 + (a).s1 * (a).s1 + (a).s2 * (a).s2 + (a).s3 * (a).s3))
	#define real4_dot(a, b) ((a).s0 * (b).s0 + (a).s1 * (b).s1 + (a).s2 * (b).s2 + (a).s3 * (b).s3)	
	inline real4 real4_normalize(real4 a)
	{
		real4 unitVector;
		real vectLength = real4_length(a);

		if (vectLength < SMALL_REAL)
		{
			unitVector.s0 = 0;
			unitVector.s1 = 0;
			unitVector.s2 = 0;
			unitVector.s3 = 0;
		}
		else
		{
			unitVector.s0 = a.s0 / vectLength;
			unitVector.s1 = a.s1 / vectLength;
			unitVector.s2 = a.s2 / vectLength;
			unitVector.s3 = a.s3 / vectLength;
		}

		return unitVector;
	}

#else		// __OPENCL_VERSION__

	#define ulong64 ulong

	#define MAX_UINT 4294967295		// 32bit
	#define MAX_INT 2147483647		// 32bit
	#define MAX_LONG 9223372036854775807	// 64bit, 0x7FFFFFFFFFFFFFFF
	#define MIN_LONG -9223372036854775808	// 64bit, 0x8000000000000000
	#define MAX_ULONG 0xffffffffffffffff	//	18446744073709551615

	// Uses functions that may map to hardware features. Precision is implementation defined.
	// Note: Native functions using the ATI Stream SDK do not always return the same results for a given input
	//#define NATIVE_FUCTIONS_ENABLE		

	#ifdef REAL_IS_DOUBLE

		#pragma OPENCL EXTENSION cl_khr_fp64 : enable	// Enable the use of double types (not all devices support doubles)
		typedef double real;		
		typedef double2 real2;
		typedef double4 real4;
		typedef double8 real8;
		typedef double16 real16;

		//http://www.khronos.org/opencl/sdk/1.0/docs/man/xhtml/macroLimits.html

		// 0x1.0p-52 from OpenCL spec
		#define EPSILON_REAL DBL_EPSILON
		//#define EPSILON_REAL FLT_EPSILON

		#define SMALL_REAL (1.0 * EPSILON_REAL)
		
		// 1.79769313486232e308 from http://msdn.microsoft.com/en-us/library/system.double.maxvalue.aspx
		//#define MAX_REAL 1.79769313486232e308 	
		// 0x1.fffffffffffffp1023 from OpenCL spec;
		#define MAX_REAL DBL_MAX 	
		//#define MAX_REAL MAXFLOAT
		#define LARGE_REAL	FLT_MAX

		//2.2250738585072014e-308 from http://msdn.microsoft.com/en-us/library/system.double.minvalue.aspx
		//#define MIN_REAL 2.2250738585072014e-308	
		// 0x1.0p-1022 from OpenCL spec; 
		#define MIN_REAL DBL_MIN	
		//#define MIN_REAL FLT_MIN

		// log base 2 of MAX_REAL
		// Use 1024 for Microsoft spec, otherwise use 4096 for OpenCL spec
		#define QUICKSORT_STACK_SIZE 1024	

		#define real4_length(a) length(a)
		#define real4_dot(a, b) dot(a, b)
		//#define real4_normalize(a) normalize(a)

		//#define real4_length(a) (sqrt((a).s0 * (a).s0 + (a).s1 * (a).s1 + (a).s2 * (a).s2 + (a).s3 * (a).s3))
		//#define real4_dot(a, b) ((a).s0 * (b).s0 + (a).s1 * (b).s1 + (a).s2 * (b).s2 + (a).s3 * (b).s3)	
		inline real4 real4_normalize(real4 a)
		{
			real4 unitVector;
			real vectLength = real4_length(a);

			if (vectLength < SMALL_REAL)
			{
				unitVector.s0 = 0;
				unitVector.s1 = 0;
				unitVector.s2 = 0;
				unitVector.s3 = 0;
			}
			else
			{
				unitVector.s0 = a.s0 / vectLength;
				unitVector.s1 = a.s1 / vectLength;
				unitVector.s2 = a.s2 / vectLength;
				unitVector.s3 = a.s3 / vectLength;
			}

			return unitVector;
		}

		//#ifdef NATIVE_FUCTIONS_ENABLE
			#define real_divide(a, b) ((a) / (b))
			#define real_rsqrt(a) (1.0/sqrt(a))
			#define real_sqrt(a) sqrt(a)
			#define real_log(a) log(a)
			#define real_powr(a, b) powr(a, b)
			#define real_tan(a) tan(a)
			#define mix(a, b, control) ((a) * (1.0 - (control)) + (b) * (control))		
			#define pown(a, b) pown((float)(a), b)
			#define powr(a, b) powr((float)(a), (float)(b))
			#define fabs(a) ((a) < 0 ? (-1.0 * (a)) : (a))
			#define clamp(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
			#define real_exp(a) exp(a)
		//#else
			//#define real_divide(a, b) ((a) / (b))
			//#define real_rsqrt(a) (1.0/sqrt(a))
			//#define real_sqrt(a) sqrt(a)
			//#define real_log(a) log(a)
			//#define real_powr(a, b) powr(a, b)
			//#define mix(a, b, control) ((a) * (1 - (control)) + (b) * (control))
			//#define pown(a, b) pown((float)(a), b)
			//#define powr(a, b) powr((float)(a), (float)(b))
			//#define fabs(a) ((a) < 0 ? (-1.0 * (a)) : (a))
			//#define clamp(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
		//#endif

	#else		// REAL_IS_DOUBLE
		//#pragma OPENCL EXTENSION cl_khr_fp64 : enable
		typedef float real;		
		typedef float2 real2;
		typedef float4 real4;
		typedef float8 real8;
		typedef float16 real16;

		// http://www.khronos.org/opencl/sdk/1.0/docs/man/xhtml/macroLimits.html

		// 1.0E-23f or less as defined by the OpenCL specification
		// Actually is 1.192093E-07
		#define EPSILON_REAL FLT_EPSILON
		#define SMALL_REAL (1.0f * EPSILON_REAL)

		// 3.402823e38 from http://msdn.microsoft.com/en-us/library/system.single.maxvalue.aspx
		// 0x1.fffffep127f from OpenCL spec.
		#define MAX_REAL MAXFLOAT
		#define LARGE_REAL	FLT_MAX

		// 1.175494351e-38F from http://msdn.microsoft.com/en-us/library/k15zsh48.aspx
		// 0x1.0p-126f from OpenCL spec. 
		#define MIN_REAL FLT_MIN	

		// log base 2 of MAX_REAL
		// Use 128 if using Microsoft spec, otherwise use 512 for OpenCL spec
		#define QUICKSORT_STACK_SIZE 512	
		
		#define real4_length(a) length(a)
		#define real4_dot(a, b) dot(a, b)

		// The built in normalize function in OpenCL has an unknown limit as to when it returns a zero for vectors of near zero length
		// Is causing discrepancies between code that uses this function with a near zero vector
		//#define real4_normalize(a) normalize(a)

		//#define real4_length(a) (sqrt((a).s0 * (a).s0 + (a).s1 * (a).s1 + (a).s2 * (a).s2 + (a).s3 * (a).s3))
		//#define real4_dot(a, b) ((a).s0 * (b).s0 + (a).s1 * (b).s1 + (a).s2 * (b).s2 + (a).s3 * (b).s3)	
		inline real4 real4_normalize(real4 a)
		{
			real4 unitVector;
			real vectLength = real4_length(a);

			if (vectLength < SMALL_REAL)
			{
				unitVector.s0 = 0;
				unitVector.s1 = 0;
				unitVector.s2 = 0;
				unitVector.s3 = 0;
			}
			else
			{
				unitVector.s0 = a.s0 / vectLength;
				unitVector.s1 = a.s1 / vectLength;
				unitVector.s2 = a.s2 / vectLength;
				unitVector.s3 = a.s3 / vectLength;
			}

			return unitVector;
		}

		#ifdef NATIVE_FUCTIONS_ENABLE
			#define real_divide(a, b) native_divide(a, b)
			#define real_rsqrt(a) native_rsqrt(a)
			#define real_sqrt(a) native_sqrt(a)
			#define real_log(a) native_log(a)
			#define real_powr(a, b) native_powr(a, b)
			#define real_exp(a) native_exp(a)
			#define real_tan(a) native_tan(a)
		#else
			#define real_divide(a, b) ((a) / (b))
			#define real_rsqrt(a) (1.0f/sqrt(a))
			#define real_sqrt(a) sqrt(a)
			#define real_log(a) log(a)
			#define real_powr(a, b) powr(a, b)
			#define real_exp(a) exp(a)
			#define real_tan(a) tan(a)
		#endif

	#endif		// REAL_IS_DOUBLE

#endif		// __OPENCL_VERSION__

#endif		// _FILE_OPTIONS_H

 

